﻿using DeHeng_Mes.Constant;
using DeHeng_Mes.Dao;
using DeHeng_Mes.LineService;
using DeHeng_Mes.Mapper;
using DeHeng_Mes.Model.Table;
using DeHeng_Mes.Utils;
using Minio.DataModel;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Speech.Synthesis.TtsEngine;
using System.Threading.Tasks;
using DateTime = System.DateTime;

namespace DeHeng_Mes.Thread
{
    public class Polling
    {
        OrderDao orderDao = new OrderDao();
        ProcessDao processDao = new ProcessDao();
        DeviceDao deviceDao = new DeviceDao();
        ErrorStatusDao errorStatusDao = new ErrorStatusDao();
        private readonly object _lock = new object();
        private readonly DataCollector dataCollector = new DataCollector();
        /// <summary>
        /// 数据采集异步线程，循环执行数据采集任务。
        /// 根据订单状态获取未采集和采集失败的订单，调用相应方法处理。
        /// </summary>
        public async Task DataAcquisition()
        {
            Tools.ProduceLogText("轮询数采线程已启动");

            while (true)
            {
                try
                {
                    // 查找订单表中符合条件的订单追溯码数据，区分为未采集和采集失败的订单
                    var orderTraces = orderDao.dataIsSave(SystemConstant.Ok);
                    var traceErr = errorStatusDao.SelectTraceNotSaves();

                    // 查询未采集和采集失败的订单
                    var notCollection = orderTraces
                        .Where(ot => !traceErr.Any(tns =>
                            string.IsNullOrEmpty(ot.FictitiousCode)
                                ? tns.TraceId == ot.TraceId
                                : tns.TraceId == ot.FictitiousCode))
                        .ToList();

                    var collectionFailed = orderTraces
                        .Where(ot => traceErr.Any(tns =>
                            string.IsNullOrEmpty(ot.FictitiousCode)
                                ? tns.TraceId == ot.TraceId
                                : tns.TraceId == ot.FictitiousCode))
                        .ToList();

                    if (notCollection.Count > 0)
                    {
                        ProcessCollectionAsync(notCollection, isFailedCollection: false);
                    }
                    {
                        ProcessCollectionAsync(collectionFailed, isFailedCollection: true);
                    }
                }
                catch (Exception ex)
                {
                    // 捕获整个轮询过程中的异常，记录日志
                    Tools.ProduceLogTextError($"DataAcquisition encountered an error: {ex.Message}");
                }

                // 设置轮询间隔时间，避免高频轮询
                await Task.Delay(SystemConstant.Polling);
            }
        }


        /// <summary>
        /// 通用的采集处理方法，用于处理未采集或采集失败的数据。
        /// </summary>
        /// <param name="orderTraces">需要处理的订单列表</param>
        /// <param name="isFailedCollection">是否为采集失败的数据</param>
        private void ProcessCollectionAsync(List<OrderTrace> traces, bool isFailedCollection)
        {
            for (int i = 0; i < traces.Count; i++)
            {
                try
                {
                    IProductionLine productionLine;

                    // 检查订单号是否有效
                    if (string.IsNullOrEmpty(traces[i].OrderId))
                    {
                        Tools.ProduceLogTextError($"轮询线程检测到一个空单号，单号ID为{traces[i].OrderId}");
                        continue;
                    }

                    string line = orderDao.GetLineType(traces[i].OrderId);
                    string materialCode = orderDao.GetActualLineType(traces[i].OrderId);

                    // 判断线体类型
                    switch (materialCode)
                    {
                        case "C34000004":
                            productionLine = new FrontProductionLine(dataCollector);
                            break;
                        case "B04340001":
                            productionLine = new SmallSecOneProductionLine(dataCollector);
                            break;
                        case "B04340007":
                            productionLine = new SmallSecTwoProductionLine(dataCollector);
                            break;
                        case "B04340008":
                            productionLine = new SmallSecThreeProductionLine(dataCollector);
                            break;
                        case "B04340009":
                            productionLine = new SmallSecFourProductionLine(dataCollector);
                            break;
                        default:
                            Tools.ProduceLogTextError($"轮询线程检测到一个非法单号，单号ID为{traces[i].OrderId}");
                            continue;
                    }

                    // 获取追溯码（根据线体类型选择 FictitiousCode 或 TraceId）
                    string code = string.IsNullOrEmpty(traces[i].FictitiousCode) ? traces[i].TraceId : traces[i].FictitiousCode;
                    string orderCode = traces[i].OrderId;

                    // 调用模块采集方法并处理状态
                    ProcessModulesAsync(productionLine, orderCode, code, line, materialCode, isFailedCollection);
                }
                catch (Exception ex)
                {
                    // 捕获每个订单的处理异常，避免影响其他订单
                    Tools.ProduceLogTextError($"匹配线体处理订单 {traces[i].OrderId} 时出错: {ex.Message}");
                }
            }

        }

        /// <summary>
        /// 遍历指定线体的采集模块集合，执行采集并记录结果或错误。
        /// </summary>
        /// <param name="productionLine">指定线体的采集模块集合</param>
        /// <param name="code">追溯码，用于数据采集</param>
        /// <param name="line">线体标识</param>
        /// <param name="orderCode">订单 ID</param> 
        private void ProcessModulesAsync(IProductionLine productionLine, string orderCode, string code, string line, string actualLine, bool isFailedCollection)
        {
            int failureCount = 0; // 记录失败模块计数
            bool createFailed = false; // 记录是否存在未创建状态
            string traceId = String.Empty;
            // 记录每种采集方法类型的上次插入次数
            var insertCountByProcessFunc = new Dictionary<Action<DateTime, string, string, string, int, int>, int>();

            traceId = orderDao.CheckTraceIdByFictitiousCode(code);
            if (string.IsNullOrEmpty(traceId))
            {
                return;
            }
            long tableIndex = HashUtils.GetHashAsInt(traceId, 10);
            // 根据采集成功或失败数量更新订单追溯码状态
            // 对采集失败的数据，根据创建时间判断是否超时并删除
            if (isFailedCollection)
            {
                var traceNotSaves = errorStatusDao.SelectByCode(code);
                traceNotSaves.RemoveAll(trace =>
                {
                    DateTime recordTime = DateTime.Parse(trace.CreateTime.ToString()).AddDays(SystemConstant.errorDay);
                    if (DateTime.Now > recordTime)
                    {
                        errorStatusDao.Delete(trace.MethodName, code); // 超时则删除记录
                        return true; // 返回 true 表示移除该元素
                    }
                    return false;
                });

                // 按 MethodName 分组
                var groupedByMethod = traceNotSaves
                    .GroupBy(trace => trace.MethodName)  // 按 MethodName 分组
                    .ToList();

                foreach (var group in groupedByMethod)
                {
                    // 检查该组是否同时包含 InsertDataIllegal 和 InsertTableIllegal
                    bool hasInsertDataIllegal = group.Any(trace => trace.Status == SystemConstant.InsertDataIllegal);
                    bool hasInsertTableIllegal = group.Any(trace => trace.Status == SystemConstant.InsertTableIllegal);

                    if (hasInsertDataIllegal && hasInsertTableIllegal)
                    {
                        // 找到 MethodName 下 Status 为 InsertTableIllegal 的项并删除
                        var traceToRemove = group.FirstOrDefault(trace => trace.Status == SystemConstant.InsertTableIllegal);
                        if (traceToRemove != null)
                        {
                            errorStatusDao.DeleteTraceNotSavePrecise(code, traceToRemove.MethodName, SystemConstant.InsertTableIllegal);  // 删除记录
                            traceNotSaves.Remove(traceToRemove);  // 从集合中移除
                        }
                    }
                }

                foreach (var trace in traceNotSaves)
                {
                    if (trace.Status == SystemConstant.InsertDataIllegal && trace.AttemptCount < ProcessConstant.MaxAttemptCount)
                    {
                        try
                        {
                            OrderStatus record = orderDao.GetOrder(orderCode);
                            ProcessDataInsertTempTable(trace.MethodName, orderCode, code, trace.process, (DateTime)record.OrderIssuedTime);
                            bool skip = ProcessDataInsertSectionTable(trace.MethodName, orderCode, code, traceId, tableIndex, true);
                            if (!skip)
                            {
                                errorStatusDao.DeleteTraceNotSavePrecise(trace.TraceId, trace.MethodName, SystemConstant.InsertDataIllegal);
                            }
                        }
                        catch (Exception ex)
                        {
                            // 捕获模块执行异常
                            Tools.ProduceLogTextError($"{line}轮询时模块 {trace.MethodName} 出现错误: {ex.Message}");
                        }
                    }
                    else if (trace.Status == SystemConstant.InsertTableIllegal && trace.AttemptCount < ProcessConstant.MaxAttemptCount)
                    {
                        try
                        {
                            bool skip = ProcessDataInsertSectionTable(trace.MethodName, orderCode, code, traceId, tableIndex, true);
                            if (!skip)
                            {
                                errorStatusDao.DeleteTraceNotSaveByTraceId(trace.TraceId);
                            }
                        }
                        catch (Exception ex)
                        {
                            // 捕获模块执行异常
                            Tools.ProduceLogTextError($"{line}轮询时模块 {trace.MethodName} 出现错误: {ex.Message}");
                        }
                    }
                }
                int insertCount = orderDao.selectOrderTraceCount(traceId);

                if (insertCount >= productionLine.UniqueProcessCount)
                {
                    orderDao.DeleteOrderTraceByTraceId(traceId);
                    errorStatusDao.DeleteTraceNotSaveByTraceId(traceId);
                }

            }
            else
            {
                foreach (var process in productionLine.Processes)
                {
                    try
                    {
                        string processName = process.Key;
                        var processConfig = process.Value;
                        var processFunc = processConfig.ProcessFunc;
                        string processFuncName = processConfig.ProcessFunc.Method.Name;
                        if (processName == "L14")
                        {

                        }
                        if (!insertCountByProcessFunc.ContainsKey(processFunc))
                        {
                            insertCountByProcessFunc[processFunc] = 0;  // 初始插入次数为 0
                        }
                        if (processFuncName == nameof(dataCollector.CollectDataForSpotWelding))
                        {
                            if (processConfig.IsFirst)
                            {
                                // 获取前一个同类型采集方法的 InsertCount
                                int previousInsertCount = insertCountByProcessFunc[processFunc];
                                //更新同类型方法的InsertCount
                                insertCountByProcessFunc[processFunc] += 1;
                                // 使用前一个插入次数和当前 BatchSize 计算本次数据量
                                int insertDataCount = previousInsertCount * processConfig.BatchSize;
                                // 执行采集模块并获取采集状态
                                processFunc(DateTime.Now, orderCode, code, processName, insertDataCount, processConfig.BatchSize);
                            }
                        }
                        if (processConfig.IsUnique)
                        {
                            ProcessDataInsertSectionTable(processFuncName, orderCode, code, traceId, tableIndex, processConfig.IsUnique);
                        }
                        if (processConfig.IsLast)
                        {
                            int insertCount = orderDao.selectOrderTraceCount(traceId);

                            if (insertCount == productionLine.UniqueProcessCount)
                            {
                                orderDao.DeleteOrderTraceByTraceId(traceId);
                                errorStatusDao.DeleteTraceNotSaveByTraceId(traceId);
                            }
                        }

                    }
                    catch (Exception ex)
                    {
                        // 捕获模块执行异常，记录日志并增加失败计数
                        Tools.ProduceLogTextError($"{line}轮询时模块 {process.Value.ProcessFunc.Method.Name} 出现错误: {ex.Message}");
                        errorStatusDao.InsertSectionFailed(process.Value.ProcessFunc.Method.Name, code);
                    }
                }
            }
        }

        /*        /// <summary>
                /// 根据追溯码更改状态
                /// </summary>
                /// <param name="code"></param>
                public void IsOkByCode(string code)
                {
                    orderDao.UpdateStatusOkByCode(code);
                }

                /// <summary>
                /// 成功采集数据，修改状态位
                /// </summary>
                /// <param name="code"></param>
                private void IsOk(int id)
                {
                    orderDao.UpdateDataStatusOk(id);
                }
                /// <summary>
                /// 将非法数据标记为错误，防止重复判断
                /// </summary>
                /// <param name="code"></param>
                private void IsError(int id)
                {
                    orderDao.UpdateDataStatusIllegal(id);
                }

                /// <summary>
                /// 未采集数据，修改状态位
                /// </summary>
                /// <param name="id"></param>
                private void IsCreateFailed(int id)
                {
                    orderDao.UpdateDataStatusNCreate(id);
                }*/

        // 根据工艺名称插入对应的数据到分表
        private bool ProcessDataInsertSectionTable(string processFuncName, string orderCode, string code, string traceId, long tableIndex, bool updateSaveCount)
        {
            bool skipCurrent = false;
            switch (processFuncName)
            {
                case "CollectDataForStudWelding":
                    var studWeldData = processDao.GetStudWeldData(code);
                    if (studWeldData.Count > 0)
                    {
                        studWeldData
                         .Where(item => item.TraceId == code)
                         .ToList()
                         .ForEach(item => item.TraceId = traceId);
                        processDao.InsertAndDeleteStudWeldData(code, studWeldData, tableIndex, updateSaveCount);
                    }
                    else
                    {
                        errorStatusDao.InsertSectionFailed(processFuncName, code);
                        skipCurrent = true;
                    }
                    break;
                case "CollectDataForGlueRemovalVision":
                    var glueRemovalData = processDao.GetGlueRemovalData(code);
                    if (glueRemovalData.Count > 0)
                    {
                        glueRemovalData.Where(item => item.TraceId == code)
                         .ToList()
                         .ForEach(item => item.TraceId = traceId);
                        processDao.InsertAndDeleteGlueRemovalVisionData(code, glueRemovalData, tableIndex, updateSaveCount);
                    }
                    else
                    {
                        errorStatusDao.InsertSectionFailed(processFuncName, code);
                        skipCurrent = true;
                    }
                    break;
                case "CollectDataForGluing":
                    var glueData = processDao.GetGlueData(code);
                    if (glueData.Count > 0)
                    {
                        glueData.Where(item => item.TraceId == code)
                         .ToList()
                         .ForEach(item => item.TraceId = traceId);
                        processDao.InsertAndDeleteGlueData(code, glueData, tableIndex, updateSaveCount);
                    }
                    else
                    {
                        errorStatusDao.InsertSectionFailed(processFuncName, code);
                        skipCurrent = true;
                    }
                    break;
                case "CollectDataForSpotWelding":
                    var spotWeldDataDeep = processDao.GetSpotWeldDataDeep(code);
                    var spotWeldData = processDao.GetSpotWeldData(code);
                    List<TraceSpotWeld> traceList = new List<TraceSpotWeld>();
                    if (spotWeldDataDeep.Count > 0)
                    {
                        foreach (var kvp in spotWeldDataDeep)
                        {
                            string key = kvp.Key; // 获取键
                            traceList = kvp.Value; // 获取值（列表）
                            traceList.Where(item => item.TraceId == code)
                         .ToList()
                         .ForEach(item => item.TraceId = traceId);
                        }
                    }
                    else if (spotWeldData.Count > 0)
                    {
                        spotWeldData.Where(item => item.TraceId == code)
                         .ToList()
                         .ForEach(item => item.TraceId = traceId);
                    }
                    var combinedList = (spotWeldData ?? new List<TraceSpotWeld>()).Concat(traceList).ToList();
                    if (combinedList.Count > 0)
                    {
                        processDao.InsertAndDeleteSpotWeldData(code, combinedList, tableIndex, updateSaveCount);
                    }
                    else
                    {
                        errorStatusDao.InsertSectionFailed(processFuncName, code);
                        skipCurrent = true;
                    }
                    break;
                case "CollectDataForGluingVision":
                    var gluingVisionData = processDao.GetGluingVisionData(code);
                    if (gluingVisionData.Count > 0)
                    {
                        gluingVisionData.Where(item => item.TraceId == code)
                         .ToList()
                         .ForEach(item => item.TraceId = traceId);
                        gluingVisionData.ForEach(item => item.OrderCode = orderCode);
                        processDao.InsertAndDeleteGlueVisionData(code, gluingVisionData, tableIndex, updateSaveCount);
                    }
                    else
                    {
                        errorStatusDao.InsertSectionFailed(processFuncName, code);
                        skipCurrent = true;
                    }
                    break;
                case "CollectDataForFds":
                    var fdsData = processDao.GetFdsData(code);
                    if (fdsData.Count > 0)
                    {
                        fdsData.Where(item => item.TraceId == code)
                         .ToList()
                         .ForEach(item => item.TraceId = traceId);
                        processDao.InsertAndDeleteFdsData(code, fdsData, tableIndex, updateSaveCount);
                    }
                    else
                    {
                        errorStatusDao.InsertSectionFailed(processFuncName, code);
                        skipCurrent = true;
                    }
                    break;
                case "CollectDataForRiveting":
                    var rivetingData = processDao.GetRivetingData(code);
                    if (rivetingData.Count > 0)
                    {
                        rivetingData.Where(item => item.TraceId == code)
                         .ToList()
                         .ForEach(item => item.TraceId = traceId);
                        //processDao
                    }
                    else
                    {
                        errorStatusDao.InsertSectionFailed(processFuncName, code);
                        skipCurrent = true;
                    }
                    break;
            }
            return skipCurrent;
        }
        //将工艺数据采集上来插入到对应的缓存表
        private void ProcessDataInsertTempTable(string funcName, string orderCode, string code = "", string line = "", DateTime retryDate = default, int dataPointer = 0, int BatchSize = 0)
        {
            if (retryDate == default)
            {
                retryDate = DateTime.MinValue;
            }
            switch (funcName)
            {
                case "CollectDataForSpotWelding":
                    dataCollector.CollectDataForSpotWelding(retryDate, orderCode, code, line, dataPointer, BatchSize);
                    break;
                case "CollectDataForGluing":
                    dataCollector.CollectDataForGluing(retryDate, orderCode, code, line, dataPointer, BatchSize);
                    break;

            }
        }

    }
}
